#include "lcd.h"

void LCD_GPIO_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	/* GPIO Ports Clock Enable */

	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_GPIOB_CLK_ENABLE();

	/*Configure GPIO pin : PB12  PB14 */
	GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_14;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	/*Configure GPIO pin : REST PA8  BLCK PA9 */
	GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	/*Configure GPIO pin Output Level  CS PB12 DC PB14 */
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12 | GPIO_PIN_14, GPIO_PIN_SET);

	/*Configure GPIO pin Output Level  REST PA8  BLCK PA9 */
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET); // 背光默认关闭
}
/******************************************************************************
	  函数说明：LCD串行数据写入函数
	  入口数据：dat  要写入的串行数据
	  返回值：  无
******************************************************************************/
void LCD_Writ_Bus(u8 dat)
{

	LCD_CS_Clr();
	HAL_SPI_Transmit(&usr_lcd_spi, &dat, 1, 1000);
	// bsp_spi2_transmit_dma(uint8_t *pTxData, uint16_t Size)
	LCD_CS_Set();
}

/******************************************************************************
	  函数说明：LCD写入数据
	  入口数据：dat 写入的数据
	  返回值：  无
******************************************************************************/
void LCD_WR_DATA8(u8 dat)
{
	LCD_Writ_Bus(dat);
}

/******************************************************************************
	  函数说明：LCD写入数据
	  入口数据：dat 写入的数据
	  返回值：  无
******************************************************************************/
void LCD_WR_DATA(u16 dat)
{
	LCD_Writ_Bus(dat >> 8);
	LCD_Writ_Bus(dat & 0xff);
}

/******************************************************************************
	  函数说明：LCD写入命令
	  入口数据：dat 写入的命令
	  返回值：  无
******************************************************************************/
void LCD_WR_REG(u8 dat)
{
	LCD_DC_Clr(); // 写命令
	LCD_Writ_Bus(dat);
	LCD_DC_Set(); // 写数据
}

/******************************************************************************
	  函数说明：设置起始和结束地址
	  入口数据：x1,x2 设置列的起始和结束地址
				y1,y2 设置行的起始和结束地址
	  返回值：  无
******************************************************************************/
void LCD_Address_Set(u16 x1, u16 y1, u16 x2, u16 y2)
{
	if (USE_HORIZONTAL == 0)
	{
		LCD_WR_REG(0x2a); // 列地址设置
		LCD_WR_DATA(x1+82);
		LCD_WR_DATA(x2+82);
		LCD_WR_REG(0x2b); // 行地址设置
		LCD_WR_DATA(y1+18);
		LCD_WR_DATA(y2+18);
		LCD_WR_REG(0x2c); // 储存器写
	}
	else if (USE_HORIZONTAL == 1)
	{
	LCD_WR_REG(0x2a); // 列地址设置
		LCD_WR_DATA(x1+82);
		LCD_WR_DATA(x2+82);
		LCD_WR_REG(0x2b); // 行地址设置
		LCD_WR_DATA(y1+18);
		LCD_WR_DATA(y2+18);
		LCD_WR_REG(0x2c); // 储存器写
	}
	else if (USE_HORIZONTAL == 2)
	{
		LCD_WR_REG(0x2a); // 列地址设置
		LCD_WR_DATA(x1+18);
		LCD_WR_DATA(x2+18);
		LCD_WR_REG(0x2b); // 行地址设置
		LCD_WR_DATA(y1+82);
		LCD_WR_DATA(y2+82);
		LCD_WR_REG(0x2c); // 储存器写
	}
	else
	{
		LCD_WR_REG(0x2a); // 列地址设置
		LCD_WR_DATA(x1+18);
		LCD_WR_DATA(x2+18);
		LCD_WR_REG(0x2b); // 行地址设置
		LCD_WR_DATA(y1+82);
		LCD_WR_DATA(y2+82);
		LCD_WR_REG(0x2c); // 储存器写
	}
}

void LCD_Init(void)
{
    LCD_GPIO_Init();     // 初始化GPIO/SPI接口（需你自己实现）
    
    LCD_RES_Clr();       // 拉低复位引脚
    HAL_Delay(30);       // 延时 >10ms
    LCD_RES_Set();       // 拉高复位引脚
    HAL_Delay(100);      // 等待芯片稳定

    LCD_BLK_Set();       // 打开背光
    HAL_Delay(100);

    // 软件复位
    LCD_WR_REG(0x01);
    HAL_Delay(120);

    // 退出睡眠
    LCD_WR_REG(0x11);
    HAL_Delay(120);

    // 设置内存数据访问控制
    LCD_WR_REG(0x36);
    if (USE_HORIZONTAL == 0)       LCD_WR_DATA8(0x00);  // 竖屏
    else if (USE_HORIZONTAL == 1)  LCD_WR_DATA8(0xC0);  // 横屏180
    else if (USE_HORIZONTAL == 2)  LCD_WR_DATA8(0x70);  // 竖屏180
    else                            LCD_WR_DATA8(0xA0);  // 横屏

    // 设置像素格式为16位色（RGB565）
    LCD_WR_REG(0x3A);
    LCD_WR_DATA8(0x05);

    // 设置Porch控制
    LCD_WR_REG(0xB2);
    LCD_WR_DATA8(0x0C);
    LCD_WR_DATA8(0x0C);
    LCD_WR_DATA8(0x00);
    LCD_WR_DATA8(0x33);
    LCD_WR_DATA8(0x33);

    // 设置Gate控制
    LCD_WR_REG(0xB7);
    LCD_WR_DATA8(0x35);

    // VCOM设置
    LCD_WR_REG(0xBB);
    LCD_WR_DATA8(0x35);

    // LCM控制
    LCD_WR_REG(0xC0);
    LCD_WR_DATA8(0x2C);

    // VDV和VRH命令使能
    LCD_WR_REG(0xC2);
    LCD_WR_DATA8(0x01);

    // VRH设置
    LCD_WR_REG(0xC3);
    LCD_WR_DATA8(0x13);

    // VDV设置
    LCD_WR_REG(0xC4);
    LCD_WR_DATA8(0x20);

    // 帧率控制（60Hz）
    LCD_WR_REG(0xC6);
    LCD_WR_DATA8(0x0F);

    // 电源控制1
    LCD_WR_REG(0xD0);
    LCD_WR_DATA8(0xA4);
    LCD_WR_DATA8(0xA1);

    // 电源控制2
    LCD_WR_REG(0xD6);
    LCD_WR_DATA8(0xA1);

    // 正极性伽马校正
    LCD_WR_REG(0xE0);
    LCD_WR_DATA8(0xF0);
    LCD_WR_DATA8(0x00);
    LCD_WR_DATA8(0x04);
    LCD_WR_DATA8(0x04);
    LCD_WR_DATA8(0x04);
    LCD_WR_DATA8(0x05);
    LCD_WR_DATA8(0x29);
    LCD_WR_DATA8(0x33);
    LCD_WR_DATA8(0x3E);
    LCD_WR_DATA8(0x38);
    LCD_WR_DATA8(0x12);
    LCD_WR_DATA8(0x12);
    LCD_WR_DATA8(0x28);
    LCD_WR_DATA8(0x30);

    // 负极性伽马校正
    LCD_WR_REG(0xE1);
    LCD_WR_DATA8(0xF0);
    LCD_WR_DATA8(0x07);
    LCD_WR_DATA8(0x0A);
    LCD_WR_DATA8(0x0D);
    LCD_WR_DATA8(0x0B);
    LCD_WR_DATA8(0x07);
    LCD_WR_DATA8(0x28);
    LCD_WR_DATA8(0x33);
    LCD_WR_DATA8(0x3E);
    LCD_WR_DATA8(0x36);
    LCD_WR_DATA8(0x14);
    LCD_WR_DATA8(0x14);
    LCD_WR_DATA8(0x29);
    LCD_WR_DATA8(0x32);

    // 设置窗口（可选）
    LCD_Address_Set(0, 0, LCD_W - 1, LCD_H - 1);

    // 清屏为黑色
    LCD_Fill(0, 0, LCD_W, LCD_H, 0x0000);

    // 打开显示
    LCD_WR_REG(0x29);
}
#define COLOR_FILL_BUFFER_SIZE 240							   // 定义缓冲区大小，可根据实际情况调整
static uint16_t color_fill_buffer[COLOR_FILL_BUFFER_SIZE * 2]; // 静态缓冲区
// GC9307
void Lcd_SendByte(uint8_t dat, LCD_DCType DC)
{

	LCD_CS_Clr();
	if (DC == LCD_DATA)
	{
		LCD_DC_Set();
	}
	else
	{
		LCD_DC_Clr();
	}
	while (HAL_SPI_GetState(&usr_lcd_spi) == HAL_SPI_STATE_BUSY_TX)
		;
	LCD_CS_Set();
}
void Lcd_SendHalfWord(uint16_t dat)
{
	uint8_t tempdat[2];
	LCD_CS_Clr();
	tempdat[0] = dat >> 8;
	tempdat[1] = dat & 0xFF;
	HAL_SPI_Transmit_DMA(&usr_lcd_spi, tempdat, 2);
	while (HAL_SPI_GetState(&usr_lcd_spi) == HAL_SPI_STATE_BUSY_TX)
		;
	LCD_CS_Set();
}
void Lcd_SendMulitiByte(uint8_t *dat, uint16_t len)
{
	LCD_CS_Clr();
	LCD_DC_Set();
	HAL_SPI_Transmit_DMA(&usr_lcd_spi, dat, len);
	while (HAL_SPI_GetState(&usr_lcd_spi) == HAL_SPI_STATE_BUSY_TX)
		;
	LCD_CS_Set();
}
void LCD_Fill(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t color)
{
    uint32_t total_pixels = (xend - xsta) * (yend - ysta);
    
    // 设置地址范围
    LCD_Address_Set(xsta, ysta, xend - 1, yend - 1);

    // 填充缓冲区（高低字节交换）
    uint16_t swapped_color = (color >> 8) | (color << 8);
    for (uint32_t i = 0; i < COLOR_FILL_BUFFER_SIZE * 2; i++) {
        color_fill_buffer[i] = swapped_color;
    }

    // 批量传输数据
    LCD_DC_Set(); // 确保处于数据写入模式
    LCD_CS_Clr();

    while (total_pixels > 0) {
        uint32_t chunk_size = (total_pixels > COLOR_FILL_BUFFER_SIZE * 2) ? COLOR_FILL_BUFFER_SIZE * 2 : total_pixels;

        // 使用 DMA 传输数据
        HAL_SPI_Transmit_DMA(&usr_lcd_spi, (uint8_t *)color_fill_buffer, chunk_size * 2);

        // 等待 DMA 传输完成
        while (HAL_SPI_GetState(&usr_lcd_spi) == HAL_SPI_STATE_BUSY_TX);

        total_pixels -= chunk_size;
    }

    LCD_CS_Set();
}
/******************************************************************************
      函数说明：显示图片
      入口数据：x,y起点坐标
                length 图片长度
                width  图片宽度
                pic[]  图片数组    
      返回值：  无
******************************************************************************/
void LCD_ShowPicture(u16 x,u16 y,u16 length,u16 width,const u8 pic[])
{
	u16 i,j;
	u32 k=0;
	LCD_Address_Set(x,y,x+length-1,y+width-1);
	for(i=0;i<length;i++)
	{
		for(j=0;j<width;j++)
		{
			LCD_WR_DATA8(pic[k*2]);
			LCD_WR_DATA8(pic[k*2+1]);
			k++;
		}
	}			
}
#define PIC_DMA_BUFFER_SIZE 512  // 定义缓冲区大小（可根据实际情况调整）
static uint8_t pic_dma_buffer[PIC_DMA_BUFFER_SIZE * 2]; // 静态缓冲区
void LCD_ShowPicture_DMA(u16 x, u16 y, u16 length, u16 width, const u8 pic[])
{
    u32 total_pixels = (u32)length * width; // 总像素数
    u32 k = 0;                              // 当前像素索引

    // 设置地址范围
    LCD_Address_Set(x, y, x + length - 1, y + width - 1);

    // 确保处于数据写入模式
    LCD_DC_Set();
    LCD_CS_Clr();

    while (total_pixels > 0)
    {
        u32 chunk_size = (total_pixels > PIC_DMA_BUFFER_SIZE) ? PIC_DMA_BUFFER_SIZE : total_pixels;

        // 填充缓冲区
        for (u32 i = 0; i < chunk_size; i++)
        {
            pic_dma_buffer[i * 2] = pic[k * 2];
            pic_dma_buffer[i * 2 + 1] = pic[k * 2 + 1];
            k++;
        }

        // 使用 DMA 传输数据
        HAL_SPI_Transmit_DMA(&usr_lcd_spi, pic_dma_buffer, chunk_size * 2);

        // 等待 DMA 传输完成
        while (HAL_SPI_GetState(&usr_lcd_spi) == HAL_SPI_STATE_BUSY_TX);

        total_pixels -= chunk_size;
    }

    // 传输完成，关闭片选信号
    LCD_CS_Set();
}